//* --------------------------------------------
//* General Data Functions ---------------------
//* --------------------------------------------
//* --------------------------------------------

// pull data from the csv file 
void initializeData(){
  
  
  
  // get and initialize data
  getInitData();
  
  // initialize main plot
  initMainPlot();
  
  //initialize controls
  initControls();
  
  numDivisions = rowCount;
  setData(true);
  
  // sort layers
  
  for (int layerID = columnCount - 1; layerID >= 0; layerID--) {
    println(layerID + ": " + data.getColumnName(controller.matchLayerIDReverse(layerID)) + " id: " + controller.matchLayerIDReverse(layerID) + " weight: " + controller.layers.get(layerID).getWeight());
  }
  
  controllerOld = controller;
  controllerPrev = controller;
  
  
  controller.sort();
  addData();
  
  println("------");
  
//  for (int layerID = columnCount - 1; layerID >= 0; layerID--) {
//    println(layerID + ": " + data.getColumnName(controller.matchLayerIDReverse(layerID)) + " id: " + controller.matchLayerIDReverse(layerID));
//  }
  
  
  
//
//  numDivisions = rowCount;
//  setData(false);
//  addData();

   computeDataMinMax();
   
  numDivisions = 34;
  setData(false);
//  println("------");
//  for (int layerID = columnCount - 1; layerID >= 0; layerID--) {
//    println(layerID + ": " + data.getColumnName(controller.matchLayerIDReverse(layerID)) + " id: " + controller.matchLayerIDReverse(layerID));
//  }
  
//  println("------");
controllerPrev = controller;
  controller.sort();
  addData();
  
  
//  for (int layerID = columnCount - 1; layerID >= 0; layerID--) {
//    println(layerID + ": " + data.getColumnName(controller.matchLayerIDReverse(layerID)) + " id: " + controller.matchLayerIDReverse(layerID));
//  }

  computeDataMinMax();
  //init controls
  initControls();

  //add color
  colorLayers();
  
  //num filters
  calculateNumFilters();
  
}


void getInitData(){
  // import data
  data = new FloatTable("tv-series.tsv");
  
  // data variables
  columnCount = data.getColumnCount();
  //columnCount--;
  rowCount = data.getRowCount();
  
  numDivisions = rowCount; //45;//36;
  numSamples = 3;
  
  dataMin = 0;
  dataMax = ceil(data.getTableMax() / 10) * 10;
  
  ////////println(dataMax);
  years = data.getRowNames();
  
  layerIDtoStroke = -1;
  highlightedLayer = -1;
  dbclickedLayer = -1;
  highlightedPoint = -1;
  
  color_integrator = new ColorIntegrator(0x00000000);
//  drawTrend = false;
  
  filterFont = createFont("Verdana", 10);
  
  graphMode = 0;
}


void setData(boolean firstTime){
  
  
  //println("numFilteredColumns : " + numFilteredColumns);
  
  controller = new Controller(numFilteredColumns, numDivisions);
  
  if(firstTime){
    for (int layerID = 0; layerID < columnCount; layerID++) {
      if(filtersChosen[layerID] == 1) controller.addLayer(layerID, numDivisions, 0x00000000);
    }
  }else{
    
    for (int layerID = 0; layerID < columnCount; layerID++) {
      ////println("layerID :" + layerID);
      if(filtersChosen[layerID] == 1) { 
        //println("layerID :" + layerID);
        if(controllerPrev.matchLayerID(layerID) != -1){
          color c = controllerPrev.getColor(controllerPrev.matchLayerID(layerID));
          controller.addLayer(layerID, numDivisions, color(red(c), green(c), blue(c), 255), false );
          for(int pos = 0; pos < numDivisions; pos++){
            if( pos <  controllerPrev.numData) {
              //println("here " +  controllerPrev.getUpperData(controllerPrev.matchLayerID(layerID), pos));
              controller.initializeUpper(layerID, pos, controllerPrev.getUpperData(controllerPrev.matchLayerID(layerID), pos) );
              controller.initializeLower(layerID, pos, controllerPrev.getLowerData(controllerPrev.matchLayerID(layerID), pos) );
            }
            else {
              int p = controllerPrev.numData - 1;
              controller.initializeUpper(layerID, pos, controllerPrev.getUpperData(controllerPrev.matchLayerID(layerID), p) );
              controller.initializeLower(layerID, pos, controllerPrev.getLowerData(controllerPrev.matchLayerID(layerID), p) );
            }
          }
        }
        else controller.addLayer(layerID, numDivisions, 0x00000000/*getColor(layerID)*/);
        
        //println(data.getColumnName(layerID));
      }
    }
    
  }
  
  
  ////println("Finished adding!!------------- " + numDivisions);
 
  numData =  rowCount; //(int)((- ltimeSliderPos + rtimeSliderPos) * mapVal);
  int numVal = (numData / numDivisions);
  
  
  int lower = 0;//(int)((ltimeSliderPos - timeScrollBarX1)*mapVal);
  int upper = rowCount;//(int)((ltimeSliderPos - timeScrollBarX1)*mapVal);
  
  
  ////////println(rowCount + "------->" + numData + " ..." + mapVal + ", " + numVal);
  
  ////////println("-ltimeSliderPos:" + ltimeSliderPos);
  int count = controller.numLayers - 1;
  for (int layerID = columnCount - 1; layerID >= 0; layerID--) {
    if(filtersChosen[layerID] == 0) continue;
    
    //if(!firstTime) println(controllerOld.matchLayerIDReverse(layerID));
    
    int rem = numData - (int)numVal * numDivisions;
    int startk = 0;
    for(int pos = 0; pos < numDivisions; pos++){
      float value = 0;
      
      ////////println("pos: " + pos + "... startk: " + startk + " ->" +(startk + numVal)+ ".... " + pos*numVal );
      ////////println("ltimeSliderPos:" + ltimeSliderPos + " timeScrollBarX1: " + timeScrollBarX1 + " calc: " + (int)((ltimeSliderPos + timeSliderDimX/2 - timeScrollBarX1)*mapVal));

      for(int k = startk; k < startk + numVal; k++){
         
         int pos1 = lower + (int)(k);
         if(firstTime) value +=  data.getFloat(pos1, layerID);
         else value += data.getFloat(pos1, controllerOld.matchLayerIDReverse(layerID));
         
         
      }
      
      ////////println("done");
      
      startk = startk + numVal;
      int toDivide = numVal;
      
      if(rem > 0){
        int pos1 = lower + (int)(startk);
        if(firstTime) value +=  data.getFloat(pos1, layerID);
         else value +=  data.getFloat(pos1, controllerOld.matchLayerIDReverse(layerID));
        rem--;
        startk++;
        toDivide += 1;
        ////////println("rem");
      }
      
      
      if(toDivide != 0) value /= (float)toDivide;
      //println(count);

      controller.setData(count, pos, value);
      
    }
    count--;
  }
  
  
//controller.sort();

Controller controller_prev = controller;
  
}

void addData(){
  
  ////println("In addData: " +  numDivisions);
  //setData();
  
  maxOffsetLayer = 0;
  maxOffset = 0;
  
  float offset = 0;
  float toffset = 0;
  for (int layerID = controller.numLayers - 1; layerID >= 0; layerID--) {
     ////println("layerID-----------> " +  layerID);
    for(int pos = 0; pos < numDivisions; pos++){
      if(pos >= numDivisions) break;
      ////println(numDivisions + " pos 1 ====== " +  pos);
      float value = controller.getRealData(layerID, pos);
      float offset_upper = 0;
      float offset_lower = 0;
      
      offset += value;
      toffset = value; 
     
      if(layerID != controller.numLayers - 1){
        offset_upper =  value + controller.getUpperOffset(layerID + 1, pos);    
        offset_lower =  controller.getUpperOffset(layerID + 1, pos);      
      }else{ 
        offset_upper =  value;
        offset_lower = 0;
      }

      controller.setUpperOffset(layerID, pos, offset_upper);
      controller.setLowerOffset(layerID, pos, offset_lower);
      
      if (toffset > maxOffset){
        maxOffsetLayer = layerID;
        maxOffset = toffset;
      }
    }
  }

   float []dev = new float[1];
   dev[0] = 0;
   float []g0_wiggle = new float[controller.numData];
   
   for(int pos = 0; pos < numDivisions; pos++){
     if(pos >= numDivisions) break;
     g0_wiggle[pos] = weightedWiggle(pos) ;
   }
   for(int pos = 0; pos < numDivisions; pos++){
     if(pos >= numDivisions) break;
     float g0 = baseline();
     //float g0 = baseline();
     if(graphMode == 1)g0 = themeRiver(pos);
     ////println("pos 2 ====== " +  pos);
     if(graphMode == 0)g0 = wiggle(pos) ;
     
     if(graphMode == 2)g0 = upstream(pos) ;
     //println(center[0]);
     
     //weighted wiggle
     //if(pos == 0) controller.setg0(pos, (g0_wiggle[pos + 1] - g0_wiggle[pos]) * 0.5);
     //else if(pos == numDivisions - 1) controller.setg0(pos, (g0_wiggle[pos]  - g0_wiggle[pos - 1]) * 0.5);
     //else controller.setg0(pos, g0_wiggle[pos]);
     controller.setg0(pos, g0); // important!

      for (int layerID = controller.numLayers - 1; layerID >= 0; layerID--) {
        ////println("pos 3 ====== " +  pos);
        float value = controller.getRealData(layerID, pos);
        float c_offset = controller.getOffset(layerID, pos);
        controller.targetUpperData(layerID, pos, controller.getg0(pos) + controller.getUpperOffset(layerID, pos));
        controller.targetLowerData(layerID, pos, controller.getg0(pos) + controller.getLowerOffset(layerID, pos));
        
      }  
   }
}


//* --------------------------------------------
//* Update Integrators -------------------------
//* --------------------------------------------
//* --------------------------------------------


void updateIntegrators(){
  for (int layerID = 0; layerID < controllerOld.numLayers; layerID++) {
    controllerOld.updateColor(layerID);
  }
  for (int layerID = 0; layerID < controller.numLayers; layerID++) {
    controller.updateColor(layerID);
    controllerOld.updateColor(layerID);
    controller.updateStrokeColor(layerID);
    controller.updateHighlightColor(layerID);
    for(int pos = 0; pos < numDivisions; pos++){
      controller.updateData(layerID, pos);
    }
  }
}

void checkIntegrators(){
  
  boolean stopLoop = true;
  float tol = 0.0005;
  for (int layerID = 0; layerID < controller.numLayers; layerID++) {
    for(int pos = 0; pos < numDivisions; pos++){
      if( !controller.checkUpperDataIntegrator(layerID, pos, tol)){ 
        stopLoop = false;
        break;
      }
      
      if( !controller.checkLowerDataIntegrator(layerID, pos, tol)){ 
        stopLoop = false;
        break;
      }
    }
    
    if( !controller.checkHighlightColorIntegrator(layerID, 2)){ 
        stopLoop = false;
        break;
      }
      
      if( !controller.checkColorIntegrator(layerID, 2)){ 
        stopLoop = false;
        break;
      }
  }
  
  if(stopLoop) {
    //drawPlot();
    noLoop();
    println("noLOOP---------------------------------------------");
  }
  
  ////////println("checking");
}


void initMainPlot(){
  // Main Plot Variables
  mainPlotX1 = 50;
  mainPlotX2 = width - 220;

  mainPlotY1 = 200;
  mainPlotY2 = height - 150;
  
  // trend view plot variables
  trendPlotX1 = mainPlotX1;
  trendPlotX2 = mainPlotX2;
  trendPlotY1 = mainPlotY1;
  trendPlotY2 = mainPlotY2;
  
  // time line
  timeLineX1 = mainPlotX1;
  timeLineX2 = mainPlotX2;
  timeLineY = mainPlotY2 + 10;
  
//  mainPlotX1 = 10;
//  mainPlotX2 = width;
//
//  mainPlotY1 = height/6;
//  mainPlotY2 = height*5/6;
}
